# -*- coding: utf-8 -*-
"""
Created on Wed Jan 21 20:33:02 2015

@author: yhadmin
"""

from Crypto.PublicKey import RSA 
import urllib 
import urllib2 
import time 
import json 
from Crypto.Signature import PKCS1_v1_5 as pk 
from Crypto.Cipher import AES
import base64 
from Crypto import Random 
from Crypto.Cipher import PKCS1_v1_5 
from Crypto.Hash import SHA

import random


#with open('./rsa_public_key.pem') as  publicfile:
#    keydata = publicfile.read()
#    publickey = RSA.importKey(keydata)
#    print publickey
publickey = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIL3fhy0WrAw3PTWFJ8rv3HqAISZBO6zqNP0R2
xdaFAOmyUSIj9b68es63t4rIsvcTD3FvVtT5tH81aGOz60nI4UhjRuGZt6L7GkiB3ZMQnFyRg+tb
+wXZzN3GuK7IXuNO//8zXQe6ZpDe4nw0xS//OmDczkFAmaeL5J85FJYxNwIDAQAB
-----END PUBLIC KEY-----"""

privatekey = """-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDWx87eZx9W/fFrh0kvRdGWJ7ETDEGUFMzSjO+lFzvGS7SBmboy
bvKe1A4GRyRXu0Y+tQpSVzS9CZYpFdlBH7pgwGXrNoJ11xX0aObW5ZR6xCW3uYB6
F6SLKIKQLPWNMf2TKOI2lKq9xCuhRFCU6tnO+sl5i342SXQGZUsF0rWrtwIDAQAB
AoGAaZiQ551xthZiBIjd/WTpN1bKY2AKOeDEFtx90gALPmHoHDPVbIhJtrbxMjr1
7kA/uALQUU1Yu3wkHI0GZFNSEOqRqCfEAEJVGv8jTsiLPGlln7m6kBPpE/7mVrG4
ecP0YtY1U1xP2iYpOCp6UcZz0Jdqq7wjnb1I5LBOTGzR73kCQQD16ofR6IK4wzPT
qxFArGfWel+YkZmRQ2+AGD2y2D8cQ1YsCStxXhG0y0XtV3Qp09OqbrzMFnw5u2r2
BHrGqbfTAkEA35Zvh59L6yNJFA0cZfD0+mm7ft23lHT0qdGm3JvgAG7vmvhyMnD0
L5M4CrxckRXxb64Umz5+F6U0k1CUehuSDQJBAL+jhTSPfU9+z2Ska017DXCW7Oh4
jrQlWT75pRs6afQchYrLmo8+P44k2tmazWvLJ6gpo/dnjmdvJmuSEhu/JwECQAew
ltllQyktJ4BHCyj+Zo6OQGKWoY+7jgahLUn9GnEpX5hG3zaY5+0S9SR5Yf2jcZBT
vmWweom5pttCNDkW5akCQGhUBj3Sq7D//M0QobmGmzCLKMKHgwgVUCdMtTvr1gDL
dffae+QyKX+cCprS5irhq71T2qjbbvOfIx8kBn5t0js=
-----END RSA PRIVATE KEY-----"""

print privatekey
merchantaccount='YB010000000xx' 
URL='www.ruyue.com' 
GUIDS={}
class MerchantAPI:
    def doPost(self,url,values): 
            ''' 
            post请求 
            参数URL 
            字典类型的参数 
            ''' 
            req = urllib2.Request(url) 
            data = urllib.urlencode(values) 
            res = urllib2.urlopen(req, data) 
            ret = res.read() 
            return ret
            
    def doGet(self,url,values): 
            ''' 
            get请求 
            参数URL 
            字典类型的参数 
            ''' 
            REQUEST = url + "?" + urllib.urlencode(values) 
            ret = urllib2.urlopen(REQUEST).read() 
            return ret    

    @staticmethod 
    def _pkcs7padding(data): 
            """ 
            对齐块 
            size 16 
            999999999=>9999999997777777 
            """ 
            size = AES.block_size 
            count = size - len(data)%size 
            if count: 
                data+=(chr(count)*count) 
            return data 
    
    @staticmethod 
    def _depkcs7padding(data): 
            """ 
            反对齐 
            """ 
            newdata = '' 
            for c in data: 
                if ord(c) > AES.block_size: 
                    newdata+=c 
            return newdata
    ''' 
    aes加密base64编码 
    ''' 
    def aes_base64_encrypt(self,data,key): 
              
            """ 
            @summary: 
                1. pkcs7padding 
                2. aes encrypt 
                3. base64 encrypt 
            @return: 
                string 
            """ 
            cipher = AES.new(key) 
            return base64.b64encode(cipher.encrypt(self._pkcs7padding(data)))
      
    def base64_aes_decrypt(self,data,key): 
            """ 
            1. base64 decode 
            2. aes decode 
            3. dpkcs7padding 
            """ 
            cipher = AES.new(key) 
            return self._depkcs7padding(cipher.decrypt(base64.b64decode(data)))
    ''' 
    rsa加密 
    '''
    
    def rsa_base64_encrypt(self,data,key): 
            ''' 
            1. rsa encrypt 
            2. base64 encrypt 
            ''' 
            cipher = PKCS1_v1_5.new(key) 
            return base64.b64encode(cipher.encrypt(data))
    ''' 
    rsa解密 
    ''' 
    def rsa_base64_decrypt(self,data,key): 
            ''' 
            1. base64 decrypt 
            2. rsa decrypt 
            示例代码 
              
           key = RSA.importKey(open('privkey.der').read()) 
            >>> 
            >>> dsize = SHA.digest_size 
            >>> sentinel = Random.new().read(15+dsize) # Let's assume that average data length is 15 
            >>> 
            >>> cipher = PKCS1_v1_5.new(key) 
            >>> message = cipher.decrypt(ciphertext, sentinel) 
            >>> 
            >>> digest = SHA.new(message[:-dsize]).digest() 
            >>> if digest==message[-dsize:]: # Note how we DO NOT look for the sentinel 
            >>> print "Encryption was correct." 
            >>> else: 
            >>> print "Encryption was not correct." 
            ''' 
            cipher = PKCS1_v1_5.new(key) 
            return cipher.decrypt(base64.b64decode(data), Random.new().read(15+SHA.digest_size)) 
              
    ''' 
    RSA签名 
    ''' 
    def sign(self,signdata): 
            ''' 
            @param signdata: 需要签名的字符串 
            ''' 
              
            h=SHA.new(signdata) 
            signer = pk.new(privatekey) 
            signn=signer.sign(h) 
            signn=base64.b64encode(signn) 
            return signn
    ''' 
    RSA验签 
    结果：如果验签通过，则返回The signature is authentic 
    如果验签不通过，则返回"The signature is not authentic." 
    ''' 
    def checksign(self,rdata): 
              
            signn=base64.b64decode(rdata.pop('sign')) 
            signdata=self.sort(rdata) 
            verifier = pk.new(publickey) 
            if verifier.verify(SHA.new(signdata), signn): 
                print "The signature is authentic." 
            else: 
                print "The signature is not authentic." 
                         
    ''' 
    请求接口前的加密过程 
    ''' 
    
    def requestprocess(self,mesdata): 
            """ 
            加密过程： 
            1、将需要的参数mes取出key排序后取出value拼成字符串signdata 
            2、用signdata对商户私钥进行rsa签名，生成签名signn，并转base64格式 
            3、将签名signn插入到mesdata的最后生成新的data 
            4、用encryptkey16位常量对data进行AES加密后转BASE64,生成机密后的data 
            5、用对方公钥publickey对encryptkey16位常量进行RSA加密BASE64编码，生成加密后的encryptkey 
            """
           # signdata=self.sort(mesdata) 
            values={}
            values['merchantaccount']=merchantaccount
            password = '1234567890123456' #app输入的密码
                         
            
            encryptkey=self.rsa_base64_encrypt(password, publickey)                     
            signdata=json.dumps(mesdata) 
            print '需要签名的字符串为：'+signdata 
            signn=self.sign(signdata)                     
            mesdata['sign']=signn
            mesdata['GUID']='abcd1234'  #app生成的
            
            data=self.aes_base64_encrypt(json.dumps(mesdata),encryptkey)
            rdata={}
            rdata['merchantaccount']=merchantaccount
            rdata['data']=data
            rdata['encryptkey']=encryptkey
            print "要发送的data",rdata
            return rdata             
           
    ''' 
    对返回结果进行解密后输出 
    ''' 
    def result_decrypt(self,result): 
            ''' 
            1、返回的结果json传给data和encryptkey两部分，都为加密后的 
            2、用商户私钥对encryptkey进行RSA解密，生成解密后的encryptkey。参考方法：rsa_base64_decrypt 
            3、用解密后的encryptkey对data进行AES解密。参考方法：base64_aes_decrypt 
            '''
            #从数据库中找到password = '1234567890123456'
            result=json.loads(result)
            account = result['merchantaccount']
            kdata=result['data'] 
            
            import db            
            password=db.find.where(username=account).password
            encryptkey = self.rsa_base64_encrypt(password,publickey) 
            if result['encryptkey']==encryptkey:
                kdata=result['data']
                rdata=self.base64_aes_decrypt(kdata,password)
                print '解密后的data='+rdata
                session_key = result['GUID']        #避免重发攻击
                if GUIDS[account] != session_key:
                   GUIDS[account]=session_key
                   return self.success()
            return self.error()
             

         
    def testCreditPayAsync(self): 
            ''' 
            生成公钥私钥对过程： 
            生成私钥：openssl genrsa -out rsa_private_key.pem 1024 
            根据私钥生成公钥： openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout 
            这时候的私钥还不能直接被使用，需要进行PKCS#8编码： 
            openssl pkcs8 -topk8 -in rsa_private_key.pem -out pkcs8_rsa_private_key.pem -nocrypt 
            命令中指明了输入私钥文件为rsa_private_key.pem，输出私钥文件为pkcs8_rsa_private_key.pem，不采用任何二次加密（-nocrypt） 
            加密过程： 
            1、将需要的参数mes取出key排序后取出value拼成字符串signdata 
            2、用signdata对商户私钥进行rsa签名，生成签名signn，并转base64格式 
            3、将签名signn插入到mes的最后生成新的data 
            4、用encryptkey16位常量对data进行AES加密后转BASE64,生成机密后的data 
            5、用对方公钥publickey对encryptkey16位常量进行RSA加密BASE64编码，生成加密后的encryptkey 
            6、将merchantaccount，第四部加密后的data，第五步加密后的encryptkey作为参数post请求给URL http://xxxx/xxx/api/xxx/xxx/xxx/xxx 
            7、返回的结果json传给data和encryptkey两部分，都为加密后的 
            8、用商户私钥对encryptkey进行RSA解密，生成解密后的encryptkey。参考方法：rsa_base64_decrypt 
            9、用解密后的encryptkey对data进行AES解密。参考方法：base64_aes_decrypt 
            ''' 
            transtime=int(time.time()) 
            od=str(Random.random.randint(10, 100000)) 
            mesdata={"merchantaccount":merchantaccount,"cardno":"xxxx758xxxx23xxxx","validthru":"04xx","cvv2":"200","phone":"1581xxxxxxx", 
            "orderid":"33hhkssseef3u"+od,"transtime":transtime,"currency":156,"amount":2,"productcatalog":"1","productname":"","productdesc":"", 
            "userip":"192.168.5.251","identityid":"ee","identitytype":6,"other":"","callbackurl":"http://IP/webtest/callback.do"} 
            values=self.requestprocess(mesdata) 
            url='http://'+URL+'/xxxx' 
            print url 
            result=self.doPost(url, values) 
            print result 
            rdata=json.loads(self.result_decrypt(result)) 
            self.checksign(rdata)